package org.example.springgobang.api;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.example.springgobang.game.OnlineUserManager;
import org.example.springgobang.game.RoomManager;
import org.example.springgobang.mapper.UserMapper;
import org.example.springgobang.model.GameReadyResponse;
import org.example.springgobang.model.GameResponse;
import org.example.springgobang.model.Room;
import org.example.springgobang.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;

@Slf4j
@Component
public class GameAPI extends TextWebSocketHandler {
    private ObjectMapper objectMapper = new ObjectMapper();

    @Autowired
    private RoomManager roomManager;

    @Autowired
    private OnlineUserManager onlineUserManager;

    @Autowired
    private UserAPI userAPI;

    @Autowired
    private UserMapper userMapper;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {

        GameReadyResponse response = new GameReadyResponse();
        //1、先获取到用户的身份信息
        User user = (User) session.getAttributes().get("user");
        if (user == null) {
            response.setOk(false);
            response.setReason("用户尚未登录");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            return;
        }
        //2、判定当前用户是否进入房间
        Room room=roomManager.getRoomByUserId(user.getUserId());
        if(room==null) {
            response.setOk(false);
            response.setReason("该玩家尚未匹配进入");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            return;
        }
        //3、判定是否已经多开 利用OnlineUserManager 如果该账号 一个在游戏大厅，一个在游戏房间也会被视为多开
        if(onlineUserManager.getGameHall(user.getUserId())!=null ||
        onlineUserManager.getGameRoom(user.getUserId())!=null) {
            response.setOk(true);
            response.setReason("禁止多开游戏");
            response.setMessage("repeatConnection");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            return;
        }
        //4、改变玩家上线 Session 信息
        onlineUserManager.enterGameRoom(user.getUserId(), session);

        //5、玩家加入对战房间 即给 room 类之中的 player1,player2 赋值 很明显存在线程安全问题
        synchronized(room){
            if (room.isAIGame()) {
                // AI对战的特殊处理
                noticeGameReady(room, room.getPlayer1(), room.getPlayer2());
                return;
            }
            if(room.getPlayer1()==null){
                room.setPlayer1(user);
                room.setWhiteUser(user.getUserId());
                log.info("玩家1:"+user.getUsername()+"已经准备就绪");
                return;
            }
            if(room.getPlayer2()==null){
                room.setPlayer2(user);
                log.info("玩家2:"+user.getUsername()+"已经准备就绪");

                //走到这一步，证明双方玩家都已经准备就绪 此时可以通知
                //通知玩家1
                noticeGameReady(room,room.getPlayer1(),room.getPlayer2());
                //通知玩家2
                noticeGameReady(room,room.getPlayer2(),room.getPlayer1());
                return;
            }
        }

        //特殊 如果存在玩家试图连接到同一个房间，就提示报错
        response.setOk(false);
        response.setReason("当前房间已满");
        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
    }

    private void noticeGameReady(Room room, User player1, User player2) throws IOException {
        GameReadyResponse response = new GameReadyResponse();
        response.setMessage("gameReady");
        response.setOk(true);
        response.setReason("");
        response.setRoomId(room.getRoomId());
        response.setThisUserId(player1.getUserId());
        response.setThatUserId(player2.getUserId());
        response.setWhiteUser(room.getWhiteUser());
        WebSocketSession session=onlineUserManager.getGameRoom(player1.getUserId());
        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        //1、先拿到身份信息
        User user = (User) session.getAttributes().get("user");
        if(user==null) {
            log.info("[handleTextMessage] 当前用户尚未登录");
            return;
        }
        //2、根据玩家id 获取到房间
        Room room=roomManager.getRoomByUserId(user.getUserId());
        room.putChess(message.getPayload());

    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        User user = (User) session.getAttributes().get("user");
        if (user == null) {
            return;
        }
        WebSocketSession tmpSession = onlineUserManager.getGameRoom(user.getUserId());
        //避免多开情况同时关闭两个会话
        if(tmpSession==session) {
            onlineUserManager.exitGameRoom(user.getUserId());
        }
        log.info("游戏房间连接异常");

        noticeThatUserWin(user);
    }



    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        User user = (User) session.getAttributes().get("user");
        if (user == null) {
            return;
        }
        WebSocketSession tmpSession = onlineUserManager.getGameRoom(user.getUserId());
        //避免多开情况同时关闭两个会话
        if(tmpSession==session) {
            onlineUserManager.exitGameRoom(user.getUserId());
        }
        log.info("当前用户"+user.getUsername()+"离开游戏房间");
        noticeThatUserWin(user);
    }

    private void noticeThatUserWin(User user) throws IOException {
        //1、先找到该玩家的房间
        Room room=roomManager.getRoomByUserId(user.getUserId());
        if(room==null) {
            log.info("房间已经销毁，无需进行后续操作");
            return;
        }
        //2、找到另一个对手
        User thatPlayer = (user==room.getPlayer1())?room.getPlayer2():room.getPlayer1();
        //3、找到对手的在线状态
        WebSocketSession session=onlineUserManager.getGameRoom(thatPlayer.getUserId());
        if (session==null){
            log.info("对面也已经掉线");
            return;
        }
        //5、构造响应高速对手你是获胜者
        GameResponse response = new GameResponse();
        response.setMessage("putChess");
        response.setUserId(thatPlayer.getUserId());
        response.setWinner(thatPlayer.getUserId());
        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));

        //5、更新玩家的分数信息
        int winPlayerId=thatPlayer.getUserId();
        int losePlayerId=user.getUserId();
        userMapper.userWin(winPlayerId);
        userMapper.userLose(losePlayerId);
        //6、释放 房间 对象
        roomManager.remove(room.getRoomId(),room.getPlayer1().getUserId(),room.getPlayer2().getUserId() );
    }
}
